﻿using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;
using System.Text.RegularExpressions;

namespace FrameWork.UI.Controls
{
    public class NbTextBox : TextBox
    {

        static NbTextBox()
        {
            //DefaultStyleKeyProperty.OverrideMetadata(typeof(NbTextBox), new FrameworkPropertyMetadata(typeof(NbTextBox)));
            ////重写Text属性改变回调方法
            //TextProperty.OverrideMetadata(typeof(NbTextBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(TextChangedCallback)));
            StyleProperty.OverrideMetadata(typeof(NbTextBox), new FrameworkPropertyMetadata(Application.Current.TryFindResource(nameof(NbTextBox))));
        }

        public NbTextBox()
        {
            //this.SetResourceReference(NbTextBox.StyleProperty, nameof(NbTextBox));
        }

        /// <summary>
        /// 
        /// </summary>
        public CornerRadius CornerRadius
        {
            get { return (CornerRadius)GetValue(CornerRadiusProperty); }
            set { SetValue(CornerRadiusProperty, value); }
        }
        public static readonly DependencyProperty CornerRadiusProperty =
            DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(NbTextBox), new PropertyMetadata(new CornerRadius(0.0)));

        /// <summary>
        /// 
        /// </summary>
        public string Placeholder
        {
            get { return (string)GetValue(PlaceholderProperty); }
            set { SetValue(PlaceholderProperty, value); }
        }
        public static readonly DependencyProperty PlaceholderProperty =
            DependencyProperty.Register("Placeholder", typeof(string), typeof(NbTextBox), new PropertyMetadata(string.Empty));

        /// <summary>
        /// 按钮图标
        /// </summary>
        public Geometry Icon
        {
            get { return (Geometry)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }
        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(Geometry), typeof(NbTextBox));


        /// <summary>
        /// 
        /// </summary>
        public string InputMode
        {
            get { return (string)GetValue(InputModeProperty); }
            set { SetValue(InputModeProperty, value); }
        }
        public static readonly DependencyProperty InputModeProperty =
            DependencyProperty.Register("InputMode", typeof(string), typeof(NbTextBox), new PropertyMetadata(string.Empty));


        /// <summary>
        /// 密码
        /// </summary>
        public string Password
        {
            get { return (string)GetValue(PasswordProperty) ?? string.Empty; }
            set { SetValue(PasswordProperty, value); }
        }
        public static readonly DependencyProperty PasswordProperty =
            DependencyProperty.Register("Password", typeof(string), typeof(NbTextBox), new PropertyMetadata("", new PropertyChangedCallback(PasswordChangedCallback)));


        /// <summary>
        /// 
        /// </summary>
        public InputCheck InputCheck
        {
            get
            {
                return (InputCheck)GetValue(InputCheckProperty);
            }
            set
            {
                SetValue(InputCheckProperty, value);
            }
        }
        public static readonly DependencyProperty InputCheckProperty =
            DependencyProperty.Register("InputCheck", typeof(InputCheck), typeof(NbTextBox),
                new FrameworkPropertyMetadata(InputCheck.Text, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, InputCheckChangedCallback));


        static void InputCheckChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var textBox = (NbTextBox)sender;
            var newValue = (InputCheck)e.NewValue;

            if (newValue == InputCheck.Double || newValue == InputCheck.Int)
                textBox.AddHandler(CommandManager.CanExecuteEvent, new RoutedEventHandler(CanPasteCommandExecuted), true);
            else
                textBox.RemoveHandler(CommandManager.CanExecuteEvent, new RoutedEventHandler(CanPasteCommandExecuted));
        }
        static void CanPasteCommandExecuted(object sender, RoutedEventArgs e)
        {
            var ce = (CanExecuteRoutedEventArgs)e;
            if (ce.Command == ApplicationCommands.Paste)
            {
                ce.CanExecute = false;
                var tb = ((NbTextBox)e.Source);
                var oldText = tb.Text;
                var oldSelSt = tb.SelectionStart;
                ce.Command.Execute(null);
                if ((tb.InputCheck == InputCheck.Int && !int.TryParse(tb.Text, out int tempInt)) ||
                    (tb.InputCheck == InputCheck.Double && !double.TryParse(tb.Text, out double tempDouble)))
                {
                    tb.Text = oldText;
                    tb.SelectionStart = oldSelSt;
                }
            }
        }


        /// <summary>
        /// 限制数字输入时，允许的最大值
        /// </summary>
        public double MaxValue
        {
            get
            {
                return (double)GetValue(MaxValueProperty);
            }
            set
            {
                SetValue(MaxValueProperty, value);
                MaxLength = value.ToString().Length;
            }
        }
        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(double), typeof(NbTextBox), new PropertyMetadata(double.MaxValue));
        /// <summary>
        /// 限制数字输入时，允许的最小值
        /// </summary>
        public double MinValue
        {
            get
            {
                return (double)GetValue(MinValueProperty);
            }
            set
            {
                SetValue(MinValueProperty, value);
            }
        }
        public static readonly DependencyProperty MinValueProperty =
            DependencyProperty.Register("MinValue", typeof(double), typeof(NbTextBox), new PropertyMetadata(double.MinValue));


        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            if (this.InputCheck == InputCheck.Int || this.InputCheck == InputCheck.Double)
            {
                var oldSelStart = this.SelectionStart;
                if (this.Text.Contains(" "))
                {
                    this.Text = this.Text.Replace(" ", "");
                    this.SelectionStart = this.Text.Length;
                }
                var val = 0d;
                if (double.TryParse(this.Text, out val))
                {
                    if (val > this.MaxValue)
                    {
                        this.Text = this.MaxValue.ToString();
                        this.SelectionStart = this.Text.Length;
                    }
                    else if (val <= this.MinValue && !this.Text.Contains("."))
                    {
                        this.Text = this.MinValue.ToString();
                        this.SelectionStart = this.Text.Length;
                    }
                }
            }
            base.OnTextChanged(e);
        }


        protected override void OnPreviewTextInput(TextCompositionEventArgs e)
        {
            var txt = this.Text.Insert(this.SelectionStart, e.Text);
            if ((this.InputCheck == InputCheck.Int || this.InputCheck == InputCheck.Double))
            {
                if (e.Text == " " ||

                    (this.MinValue >= 0 && this.SelectionStart == 0 && e.Text == "-"))
                    e.Handled = true;

                if (e.Handled == false)
                {
                    if (this.InputCheck == InputCheck.Int)
                    {
                        e.Handled = !Regex.IsMatch(txt, @"^(-|\+)?(\d)*$");
                    }
                    else if (this.InputCheck == InputCheck.Double)
                    {
                        e.Handled = !(Regex.IsMatch(txt, @"^(-|\+)?(\d)*$") ||
                            Regex.IsMatch(txt, @"^(-|\+)?(\d)+(\.){0,1}(\d)*$"));
                    }
                }

            }
            base.OnPreviewTextInput(e);
        }

        private void CommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = false;
            e.Handled = true;
        }

        protected override void OnLostFocus(RoutedEventArgs e)
        {
            if (this.InputCheck == InputCheck.Int || this.InputCheck == InputCheck.Double)
            {
                if (!string.IsNullOrEmpty(this.Text))
                {
                    if (!double.TryParse(this.Text, out double val))
                    {
                        this.Text = this.MinValue.ToString();
                    }
                    else
                    {
                        if (val > this.MaxValue)
                            this.Text = this.MaxValue.ToString();
                        else if (val <= this.MinValue)
                            this.Text = this.MinValue.ToString();
                        this.SelectionStart = this.Text.Length;
                    }
                }
            }
            base.OnLostFocus(e);
        }


        //Text属性改变回调方法
        private static void TextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            NbTextBox instance = (NbTextBox)d;
            if (instance.InputMode != "Password")
                return;
            //新的前端密码文本
            string text = e.NewValue.ToString();
            //已键入的文本长度
            int textLength = text.Length;
            //已保存的密码长度
            int psdLength = instance.Password == null ? 0 : instance.Password.Length;
            //判断密码是否已修改
            if (textLength == psdLength && text == new string(instance.PasswordChar, text.Length)) return;
            //记住光标位置(设置完Text后会丢失，所以现在要记住)
            int selectionStart = instance.SelectionStart;
            //起始修改位置
            int startIndex = -1;
            for (int i = 0; i < textLength; i++)
            {
                if (text[i] != instance.PasswordChar)
                {
                    startIndex = i;
                    break;
                }
            }
            //结束修改位置
            int stopIndex = -1;
            for (int i = textLength - 1; i >= 0; i--)
            {
                if (text[i] != instance.PasswordChar)
                {
                    stopIndex = i;
                    break;
                }
            }
            //添加或修改了一个或连续的多个值
            if (startIndex != -1)
            {
                //累计修改长度
                int alterLength = stopIndex - startIndex + 1;
                //长度没变化，单纯的修改了一个或连续的多个值
                if (textLength == psdLength)
                {
                    instance.Password = instance.Password.Substring(0, startIndex) + text.Substring(startIndex, alterLength) + instance.Password.Substring(stopIndex + 1);
                }
                //新增了内容
                else
                {
                    //新增且修改了原来内容
                    if (alterLength > textLength - psdLength)
                    {
                        //计算未修改密码个数 textLength - alterLength
                        //计算已修改密码个数 = 原密码长度 - 未修改密码个数 psdLength - (textLength - alterLength)
                        //原密码该保留的后半部分的索引 = 已修改密码个数 + 起始修改位置
                        instance.Password = instance.Password.Substring(0, startIndex) + text.Substring(startIndex, alterLength) + instance.Password.Substring(psdLength - (textLength - alterLength) + startIndex);
                    }
                    //单纯的新增了一个或多个连续的值
                    else
                    {
                        instance.Password = instance.Password.Substring(0, startIndex) + text.Substring(startIndex, alterLength) + instance.Password.Substring(startIndex);
                    }

                }
            }
            //删除了一个或连续的多个值
            else
            {
                //已删除的数据长度	SelectionStart 为 TextBox 的属性(获取或设置当前所选内容的起始位置的字符索引)
                int length = psdLength - textLength;
                if (instance.SelectionStart < textLength)
                {

                    //改变了中间的数据
                    instance.Password = instance.Password.Substring(0, instance.SelectionStart) + instance.Password.Substring(instance.SelectionStart + length);
                }
                else
                {
                    //删除了结尾的数据
                    instance.Password = instance.Password.Substring(0, instance.SelectionStart);
                }
            }
            //设置光标位置
            instance.SelectionStart = selectionStart;
        }
        private static void PasswordChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            NbTextBox instance = (NbTextBox)d;
            if (e.NewValue != null && instance.InputMode == "Password")
                instance.Text = new string(instance.PasswordChar, e.NewValue.ToString().Length);
        }
        /// <summary>
        /// 密码显示字符
        /// </summary>
        public char PasswordChar
        {
            get { return (char)GetValue(PasswordCharProperty); }
            set { SetValue(PasswordCharProperty, value); }
        }
        public static readonly DependencyProperty PasswordCharProperty =
            DependencyProperty.Register("PasswordChar", typeof(char), typeof(NbTextBox), new PropertyMetadata('●'));
    }

    public enum InputCheck
    {
        Text = 0,
        Int = 1,
        Double = 2
    }
}
